#!

# This is statement is required by the build system to query build info
if __name__ == '__build__':
    raise Exception

import string
__version__ = string.split('$Revision: 1.1.1.1 $')[1]
__date__ = string.join(string.split('$Date: 2007/02/15 19:25:21 $')[1:3], ' ')
__author__ = 'Tarn Weisner Burton <twburton@users.sourceforge.net>'

#
# Ported to PyOpenGL 2.0 by Tarn Weisner Burton 10May2001
#
# This code was created by Richard Campbell '99 (ported to Python/PyOpenGL by John Ferguson 2000)
#
# The port was based on the PyOpenGL tutorial module: dots.py  
#
# If you've found this code useful, please let me know (email John Ferguson at hakuin@voicenet.com).
#
# See original source and C based tutorial at http://nehe.gamedev.net
#
# Note:
# -----
# This code is not a good example of Python and using OO techniques.  It is a simple and direct
# exposition of how to use the Open GL API in Python via the PyOpenGL package.  It also uses GLUT,
# which in my opinion is a high quality library in that it makes my work simpler.  Due to using
# these APIs, this code is more like a C program using function based programming (which Python
# is in fact based upon, note the use of closures and lambda) than a "good" OO program.
#
# To run this code get and install OpenGL, GLUT, PyOpenGL (see http://www.python.org), and NumPy.
# Installing PyNumeric means having a C compiler that is configured properly, or so I found.  For 
# Win32 this assumes VC++, I poked through the setup.py for Numeric, and chased through disutils code
# and noticed what seemed to be hard coded preferences for VC++ in the case of a Win32 OS.  However,
# I am new to Python and know little about disutils, so I may just be not using it right.
#
# NumPy is not a hard requirement, as I am led to believe (based on skimming PyOpenGL sources) that
# PyOpenGL could run without it. However preformance may be impacted since NumPy provides an efficient
# multi-dimensional array type and a linear algebra library.
#
# BTW, since this is Python make sure you use tabs or spaces to indent, I had numerous problems since I 
# was using editors that were not sensitive to Python.
#
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import sys
from numpy import *
from numpy.random import *

# Some api in the chain is translating the keystrokes to this octal string
# so instead of saying: ESCAPE = 27, we use the following.
ESCAPE = '\033'

# Number of the glut window.
window = 0

# Rotation angle for the triangle. 
rtri = 0.0

# Rotation angle for the quadrilateral.
rquad = 0.0

n=50

# A general OpenGL initialization function.  Sets all of the initial parameters. 
def InitGL(Width, Height):                # We call this right after our OpenGL window is created.
    glClearColor(0.0, 0.0, 0.0, 0.0)    # This Will Clear The Background Color To Black
    glClearDepth(1.0)                    # Enables Clearing Of The Depth Buffer
    glDepthFunc(GL_LESS)                # The Type Of Depth Test To Do
    glEnable(GL_DEPTH_TEST)                # Enables Depth Testing
    glShadeModel(GL_SMOOTH)                # Enables Smooth Color Shading
    
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()                    # Reset The Projection Matrix
                                        # Calculate The Aspect Ratio Of The Window
    #gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)

    #glMatrixMode(GL_MODELVIEW)
    return

# The function called when our window is resized (which shouldn't happen if you enable fullscreen, below)
def ReSizeGLScene(Width, Height):
    if Height == 0:                        # Prevent A Divide By Zero If The Window Is Too Small 
        Height = 1

    glViewport(0, 0, Width, Height)        # Reset The Current Viewport And Perspective Transformation
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    #gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)
    #glMatrixMode(GL_MODELVIEW)
    return

# The main drawing function. 
def DrawGLScene():
    global rtri, rquad
    
    # Clear The Screen And The Depth Buffer
    #glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
   # glLoadIdentity()                    # Reset The View 

#    # Move Left 1.5 units and into the screen 6.0 units.
#    glTranslatef(-1.5, 0.0, -6.0)
#
#    # We have smooth color mode on, this will blend across the vertices.
#    # Draw a triangle rotated on the Y axis. 
#    glRotatef(rtri, 0.0, 1.0, 0.0)      # Rotate
#    glBegin(GL_POLYGON)                 # Start drawing a polygon
#    glColor3f(1.0, 0.0, 0.0)            # Red
#    glVertex3f(0.0, 1.0, 0.0)           # Top
#    glColor3f(0.0, 1.0, 0.0)            # Green
#    glVertex3f(1.0, -1.0, 0.0)          # Bottom Right
#    glColor3f(0.0, 0.0, 1.0)            # Blue
#    glVertex3f(-1.0, -1.0, 0.0)         # Bottom Left
#    glEnd()                             # We are done with the polygon
 
#    # Somewhere before the drawing code
#    circle = [[radius*math.sin(math.radians(deg)), radius*math.cos(math.radians(deg)), 0.0] for deg in xrange(360)]
#           
#    # Generate Buffers (inside Init method)
#    circle = array(circle, dtype=float32)
#    vertex_vbo = GL.GLuint(0)
#    glGenBuffers(1, vertex_vbo)
#    glBindBuffer(GL_ARRAY_BUFFER, circle)
#    glBufferData(GL_ARRAY_BUFFER, ADT.arrayByteCount(circle), ADT.voidDataPointer(circle), GL_STATIC_DRAW_ARB)
#            
#    # Draw buffers (inside Render method)
#    glBindBuffer(GL_ARRAY_BUFFER, vertex_vbo)
#    glVertexPointer(3, GL_FLOAT, 0, None)
#    glDrawArrays(GL_LINE_STRIP, 0, circle.shape[0])
           
    # We are "undoing" the rotation so that we may rotate the quad on its own axis.
    # We also "undo" the prior translate.  This could also have been done using the
    # matrix stack.
    #glLoadIdentity()
    
    # Move Right 1.5 units and into the screen 6.0 units.
#    glTranslatef(1.5, 0.0, -6.0)

#    # Draw a square (quadrilateral) rotated on the X axis.
#    glRotatef(rquad, 1.0, 0.0, 0.0)        # Rotate 
#    glColor3f(0.3, 0.5, 1.0)            # Bluish shade
#    glBegin(GL_QUADS)                   # Start drawing a 4 sided polygon
#    glVertex3f(-1.0, 1.0, 0.0)          # Top Left
#    glVertex3f(1.0, 1.0, 0.0)           # Top Right
#    glVertex3f(1.0, -1.0, 0.0)          # Bottom Right
#    glVertex3f(-1.0, -1.0, 0.0)         # Bottom Left
#    glEnd()                             # We are done with the polygon

    # What values to use?  Well, if you have a FAST machine and a FAST 3D Card, then
    # large values make an unpleasant display with flickering and tearing.  I found that
    # smaller values work better, but this was based on my experience.
    #rtri  = rtri + 1.0                  # Increase The Rotation Variable For The Triangle
    #rquad = rquad - 1.0                 # Decrease The Rotation Variable For The Quad
    
    n = 1000
    
    w = 0.002
    h = 1.
    x = -1. + arange(n)*w
    y = (random(n)-0.5)*0.3 - 0.5
    
    vertex = zeros((n,4,2))
    vertex[:,0,0] = x
    vertex[:,0,1] = y + h
    vertex[:,1,0] = x + w
    vertex[:,1,1] = y + h
    vertex[:,2,0] = x + w
    vertex[:,2,1] = y
    vertex[:,3,0] = x
    vertex[:,3,1] = y
        
    c = random(n)
    
    color = ones((n,4,3))
    color[:,0,1] = c
    color[:,1,1] = c
    color[:,2,1] = c
    color[:,3,1] = c
    color[:,0,2] = c
    color[:,1,2] = c
    color[:,2,2] = c
    color[:,3,2] = c
    #color = array([[1,c[0],c[0]],[1,c[1],c[1]]]).repeat(4,axis=0)
    #color.shape = (4*n, 3)
    
    glVertexPointerd(vertex)
    glColorPointerd(color)
    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_COLOR_ARRAY)
    
    glClearColor(1, 1, 1, 0)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    #glOrtho(-1, 1, -1, 1, -1, 1)
    #glDisable(GL_LIGHTING)
    glDrawArrays(GL_QUADS, 0, 4*n)
    #glEnable(GL_LIGHTING)

    #  since this is double buffered, swap the buffers to display what just got drawn. 
    glutSwapBuffers()

# The function called whenever a key is pressed. Note the use of Python tuples to pass in: (key, x, y)  
def keyPressed(*args):
    # If escape is pressed, kill everything.
    if args[0] == ESCAPE:
        sys.exit()

def main():
    global window
    glutInit(sys.argv)

    # Select type of Display mode:   
    #  Double buffer 
    #  RGBA color
    # Alpha components supported 
    # Depth buffer
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
    
    # get a 640 x 480 window 
    glutInitWindowSize(640, 480)
    
    # the window starts at the upper left corner of the screen 
    glutInitWindowPosition(0, 0)
    
    # Okay, like the C version we retain the window id to use when closing, but for those of you new
    # to Python (like myself), remember this assignment would make the variable local and not global
    # if it weren't for the global declaration at the start of main.
    window = glutCreateWindow("Jeff Molofee's GL Code Tutorial ... NeHe '99")

       # Register the drawing function with glut, BUT in Python land, at least using PyOpenGL, we need to
    # set the function pointer and invoke a function to actually register the callback, otherwise it
    # would be very much like the C version of the code.    
    glutDisplayFunc(DrawGLScene)
    
    # Uncomment this line to get full screen.
    # glutFullScreen()

    # When we are doing nothing, redraw the scene.
    glutIdleFunc(DrawGLScene)
    
    # Register the function called when our window is resized.
    glutReshapeFunc(ReSizeGLScene)
    
    # Register the function called when the keyboard is pressed.  
    glutKeyboardFunc(keyPressed)

    # Initialize our window. 
    InitGL(640, 480)

    # Start Event Processing Engine    
    glutMainLoop()

# Print message to console, and kick off the main to get it rolling.
print("Hit ESC key to quit.")
main()
        
